You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Added multi-tenant UX support to BotSharp-UI. When multi-tenancy is enabled, the login flow loads a selectable tenant list from the BotSharp backend and sends the selected tenant id via __tenant request header. After login, the selected tenant name is displayed in the top-right user area to make the active tenant context explicit.
PR Type
Enhancement, UI
Description
Login UX
Fetch tenant options from backend: GET /tenants/options
Render a tenant selector on the login page when options are available
Require tenant selection before submitting login
Include selected tenant id in all auth-related requests (and subsequent API calls) via __tenant header
Post-login UX
Persist selected tenant id/name in client-side state (e.g., store/state manager)
Display current tenant name in the top-right header area (near user avatar/menu)
Backward compatibility
When multi-tenancy is disabled on server, /tenants/options returns empty array and UI falls back to original single-tenant login without tenant selector
If tenant options request fails, UI should either show a non-blocking error or gracefully fall back (depending on existing UX pattern)
Backend dependency
Tenant options endpoint
GET /tenants/options
Response: [{ tenantId: string, name: string }]
Tenant header
Request header: __tenant: <tenantId>
The server resolves current tenant from the header (and scopes it via middleware) before executing downstream services
Flow Walkthrough
sequenceDiagram
participant UI as BotSharp-UI
participant API as BotSharp API
UI->>API: GET /tenants/options
API-->>UI: [{tenantId, name}] or []
alt multi-tenant enabled (non-empty)
UI->>UI: user selects tenant
UI->>API: POST /auth/login with header __tenant: <tenantId>
API-->>UI: token / session
UI->>UI: persist token + tenantName
UI->>API: subsequent API calls with header __tenant: <tenantId>
UI->>UI: show tenantName in top-right header
else disabled / empty list
UI->>API: POST /auth/login (original payload)
API-->>UI: token / session
end
Loading
Testing
Multi-tenant enabled
Login page shows tenant selector
Selecting tenant and logging in sends __tenant header
After login, header shows tenant name
Multi-tenant disabled
Tenant selector not shown
Login behavior unchanged
Edge cases
/tenants/options returns empty: treat as single-tenant
Add multi-tenant support to login flow with tenant selector
Persist tenant ID/name in session storage and display in header
Include tenant ID in all API requests via __tenant header
Gracefully handle single-tenant and multi-tenant scenarios
Diagram Walkthrough
flowchart LR
A["Login Page"] -->|GET /tenants/options| B["Backend API"]
B -->|Tenant List| C["Render Tenant Selector"]
C -->|User Selects Tenant| D["Submit Login with __tenant Header"]
D -->|POST /auth/login| B
B -->|Auth Token| E["Store Tenant ID/Name"]
E -->|Display in Header| F["Header Component"]
G["All API Requests"] -->|Include __tenant Header| B
Loading
File Walkthrough
Relevant files
Enhancement
+page.svelte
Add tenant selector and multi-tenant login flow
src/routes/(authentication)/login/+page.svelte
Import getTenantOptions from auth service and tenant store helpers
Add tenant selector dropdown UI that renders when tenant options available
Fetch tenant options on component mount and before form submission
Validate tenant selection before allowing login when multi-tenancy enabled
Pass selected tenant ID to getToken() and persist tenant name after successful login
Generic: Meaningful Naming and Self-Documenting Code
Objective: Ensure all identifiers clearly express their purpose and intent, making code self-documenting
Status: Misspelled function name: The new function name getTenamtOptions() is misspelled, reducing readability and increasing the chance of future mistakes.
Referred Code
await getTenamtOptions();
});
function handleRememberMe(){
if(isRememberMe){
localStorage.setItem("user_name", username);
}
else {
localStorage.removeItem("user_name");
}
}
/** @param {any} e */
async function onSubmit(e) {
isSubmitting=true;
handleRememberMe();
e.preventDefault();
// Ensure tenant options have been fetched at least onceif (!tenantOptionsLoaded) {
awaitgetTenamtOptions();
}
... (clipped67lines)
Generic: Robust Error Handling and Edge Case Management
Objective: Ensure comprehensive error handling that provides meaningful context and graceful degradation
Status: Silent error paths: Tenant option fetch and missing-tenant selection failures are handled silently (catch clears state; submit returns early) without actionable user feedback or logging for diagnosis.
Referred Code
// Ensure tenant options have been fetched at least once
if (!tenantOptionsLoaded) {
awaitgetTenamtOptions();
}
if (tenantOptions?.length > 0 && !tenantId) {
isSubmitting=false;
return;
}
await getToken(username, password, tenantOptions?.length > 0 ? tenantId : '', () => {
isOpen=true;
msg='Authentication success';
status='success';
if (tenantOptions?.length>0) {
const selected =tenantOptions.find((x) =>x.tenantId===tenantId);
setTenantName(selected?.name||'');
} else {
clearTenantName();
}
... (clipped49lines)
Objective: To create a detailed and reliable record of critical system actions for security analysis and compliance.
Status: Missing audit logging: The PR introduces tenant-scoped authentication behavior but the diff contains no explicit audit logging for login/tenant-selection events, which may be handled elsewhere outside the visible UI code.
Generic: Security-First Input Validation and Data Handling
Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent vulnerabilities
Status: Tenant ID trust: The PR adds the __tenant header to all requests from a client-side stored value, which requires confirmation that the backend strictly validates authorization for the tenant and does not trust the header alone.
Referred Code
axios.interceptors.request.use((config)=>{// Add your authentication logic hereconstuser=getUserStore();consttenantId=getTenantId();if(!skipLoader(config)){loaderStore.set(true);}// Attach an authentication token to the request headersif(user.token){config.headers.Authorization=`Bearer ${user.token}`;if(tenantId){config.headers['__tenant']=tenantId;}}else{retryQueue.queue=[];redirectToLogin();}returnconfig;
Refactor the tenant state management to use a Svelte writable store instead of direct sessionStorage access and global window events. This change would align with the application's existing architecture, centralize state logic, and improve reactivity.
Why: The suggestion correctly identifies a significant architectural inconsistency; the PR introduces a manual state management system using sessionStorage and global events, which is contrary to the established Svelte store pattern already used in the application, impacting maintainability and code quality.
Medium
Possible issue
Fix typo in function definition
Correct the typo in the function definition from getTenamtOptions to getTenantOptions.
-async function getTenamtOptions() {+async function getTenantOptions() {
try {
let data = await getTenantOptions();
const raw = Array.isArray(data) ? data : [];
tenantOptions = raw
.map((/** @type {any} */ x) => ({
tenantId: x?.tenantId || x?.id || '',
name: x?.name || x?.tenantName || x?.displayName || x?.id || x?.tenantId || ''
}))
.filter((/** @type {{tenantId: string}} */ x) => !!x.tenantId);
if (tenantOptions.length === 0) {
...
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 8
__
Why: This suggestion correctly identifies a typo in the function definition getTenamtOptions which would cause a runtime error. Fixing this critical bug is important for the feature to work correctly.
Medium
Add tenant selection validation
Add user feedback when tenant selection is required but a tenant has not been selected.
if (tenantOptions?.length > 0 && !tenantId) {
isSubmitting = false;
+ msg = 'Please select a tenant';+ status = 'danger';+ isOpen = true;
return;
}
Apply / Chat
Suggestion importance[1-10]: 7
__
Why: This suggestion improves user experience by providing feedback when a required tenant is not selected, preventing a silent failure. This is a valuable enhancement to the login flow.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
User description
User description
Added multi-tenant UX support to BotSharp-UI. When multi-tenancy is enabled, the login flow loads a selectable tenant list from the BotSharp backend and sends the selected tenant id via
__tenantrequest header. After login, the selected tenant name is displayed in the top-right user area to make the active tenant context explicit.PR Type
Enhancement, UI
Description
Login UX
GET /tenants/options__tenantheaderPost-login UX
Backward compatibility
/tenants/optionsreturns empty array and UI falls back to original single-tenant login without tenant selectorBackend dependency
Tenant options endpoint
GET /tenants/options[{ tenantId: string, name: string }]Tenant header
__tenant: <tenantId>Flow Walkthrough
sequenceDiagram participant UI as BotSharp-UI participant API as BotSharp API UI->>API: GET /tenants/options API-->>UI: [{tenantId, name}] or [] alt multi-tenant enabled (non-empty) UI->>UI: user selects tenant UI->>API: POST /auth/login with header __tenant: <tenantId> API-->>UI: token / session UI->>UI: persist token + tenantName UI->>API: subsequent API calls with header __tenant: <tenantId> UI->>UI: show tenantName in top-right header else disabled / empty list UI->>API: POST /auth/login (original payload) API-->>UI: token / session endTesting
Multi-tenant enabled
__tenantheaderMulti-tenant disabled
Edge cases
/tenants/optionsreturns empty: treat as single-tenant/tenants/optionsfails: fallback behavior matches existing UI error handlingPR Type
Enhancement
Description
Add multi-tenant support to login flow with tenant selector
Persist tenant ID/name in session storage and display in header
Include tenant ID in all API requests via
__tenantheaderGracefully handle single-tenant and multi-tenant scenarios
Diagram Walkthrough
File Walkthrough
+page.svelte
Add tenant selector and multi-tenant login flowsrc/routes/(authentication)/login/+page.svelte
getTenantOptionsfrom auth service and tenant store helpersavailable
enabled
getToken()and persist tenant name aftersuccessful login
Header.svelte
Display current tenant name in headersrc/routes/VerticalLayout/Header.svelte
getTenantNamefrom store helperstenantChangedcustom event to update displayed tenant namedropdowns
http.js
Include tenant ID in all HTTP requestssrc/lib/helpers/http.js
getTenantIdfrom store helpers__tenantheader to all axios requests when tenant ID is availableauthentication
store.js
Add tenant state management functionssrc/lib/helpers/store.js
tenantKeyandtenantNameKeyconstants for session storagegetTenantId(),setTenantId(),clearTenantId()functionsgetTenantName(),setTenantName(),clearTenantName()functions
notifyTenantChanged()to dispatch custom event for tenant changesresetStorage()to clear tenant data when resetting user sessionauth-service.js
Add tenant parameter to auth functionssrc/lib/services/auth-service.js
getToken()to accepttenantIdparameter and include in authheaders
renewToken()to include__tenantheader when tenant ID existsgetTenantOptions()function to fetch available tenants frombackend
api-endpoints.js
Add tenant options API endpointsrc/lib/services/api-endpoints.js
userTenantsUrlendpoint constant pointing to/tenants/options